package com.jolink.omiis.wechat.token;

import java.util.HashMap;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.google.gson.JsonObject;
import com.jolink.omiis.wechat.api.impl.WeChatApiBaseService;
import com.jolink.omiis.wechat.keys.IPreferences;
import com.jolink.omiis.wechat.redis.IRedisProcessor;
import com.jolink.omiis.wechat.redis.RedisClusterProcessor;
import com.jolink.omiis.wechat.util.DateUtil;
import com.jolink.omiis.wechat.util.GsonUtil;

@Component
public class ComponentAccessTokenObserver extends WeChatApiBaseService implements Observer {

	private static final Logger logger = LoggerFactory.getLogger(ComponentAccessTokenObserver.class);

	private String uri = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";

	/*
	 * (non-Javadoc) 更新 ComponentAccessToken
	 * 
	 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
	 */
	@Override
	public void update(Observable o, Object arg) {
		Map<String, String> componentInfo = getContext().getCompentInfo();
		logger.info("收到腾讯Ticket请求，开始更新ComponentAccessToken，服务平台信息：{}。", componentInfo);
		long t1 = System.currentTimeMillis();
		if (arg instanceof ComponentVerifyTicket) {
			ComponentVerifyTicket cvt = (ComponentVerifyTicket) arg;
			JsonObject params = new JsonObject();
			params.addProperty("component_appid", componentInfo.get(IPreferences.COMPONENT_APP_ID));
			params.addProperty("component_appsecret", componentInfo.get(IPreferences.APP_SECRET));
			params.addProperty("component_verify_ticket", cvt.getComponentVerifyTicket());
			String requestBody = GsonUtil.jsonElement2Json(params);
			logger.info("发送申请ComponentAccessToken请求内容：{}。", requestBody);
			String result = executePost(uri, "", requestBody);
			Map<String, String> tokenMap = result2Map(result);
			if (tokenMap == null || tokenMap.isEmpty()) {
				logger.info("调用腾讯服务刷新ComponentAccessToken失败。");
				return;
			}
			logger.info("获取腾讯平台返回的ComponentAccessToken结果：{}，str2Map：{}。", result, tokenMap);
			if (tokenMap.containsKey("errcode")) {
				logger.error("获取服务平台ComponentAccessToken失败，错误信息：{}。", tokenMap);
				return;
			}
			tokenMap.put("app_id", cvt.getAppId());
			tokenMap.put("app_secret", componentInfo.get(IPreferences.APP_SECRET));
			tokenMap.put("token", componentInfo.get(IPreferences.TOKEN));
			tokenMap.put("encrypt_key", componentInfo.get(IPreferences.ENCRYPT_KEY));
			tokenMap.put("ticket", cvt.getComponentVerifyTicket());
			tokenMap.put("access_token_expires", tokenMap.get("expires_in"));
			Map<String, String> preAuthCodeMap = queryPreAuthCode(tokenMap);
			if (preAuthCodeMap.containsKey("errcode")) {
				logger.error("获取服务平台PreAuthCode失败，错误信息：{}。", tokenMap);
			} else {
				tokenMap.putAll(queryPreAuthCode(tokenMap));
			}
			componentInfo.putAll(tokenMap);
			logger.info("服务平台Token刷新完成，Token信息：{}。", componentInfo);
			{
				tokenMap.put("access_token_update_timestamp", DateUtil.getCurrentTimeMillis());
				tokenMap.put("access_token_update_time", DateUtil.getCurrentDate());
			}
			sync2Redis(IPreferences.COMPONENT_ID, tokenMap);
		}
		long t2 = System.currentTimeMillis();
		logger.info("更新服务平台ComponentAccessToken完成，耗时：{}毫秒。", (t2 - t1));
	}

	private Map<String, String> queryPreAuthCode(Map<String, String> tokenMap) {
		logger.info("开始向腾讯服务器申请预授权码......");
		long t1 = System.currentTimeMillis();
		String url = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode";
		Map<String, String> reqParams = new HashMap<String, String>();
		reqParams.put("component_access_token", tokenMap.get("component_access_token"));
		JsonObject body = new JsonObject();
		body.addProperty("component_appid", tokenMap.get("app_id"));
		String requestBodyStr = GsonUtil.jsonElement2Json(body);
		logger.info("向腾讯服务器发送申请预授权码的请求内容：{}。", requestBodyStr);
		String result = (String) executePost(url, reqParams, requestBodyStr);
		Map<String, String> preAuthCodeMap = result2Map(result);
		logger.info("腾讯服务器返回预授权码结果：{}，str2Map：{}。", result, preAuthCodeMap);
		if (preAuthCodeMap.containsKey("errcode")) {
			logger.error("获取ComponentAccessToken失败，错误信息：{}", preAuthCodeMap);
			return preAuthCodeMap;
		}
		long t2 = System.currentTimeMillis();
		logger.info("申请服务平台预授权码成功，耗时：{}毫秒。", (t2 - t1));
		return preAuthCodeMap;
	}

	private void sync2Redis(String key, Map<String, String> values) {
		long t1 = System.currentTimeMillis();
		logger.info("同步Token信息：{}至Redis。", values);
		IRedisProcessor redisProcessor = new RedisClusterProcessor();
		try {
			redisProcessor.hmset(key, values);
		} catch (Exception e) {
			logger.error("存储Redis信息失败，" + e.getMessage(), e);
			return;
		}
		long t2 = System.currentTimeMillis();
		logger.info("存储数据至Redis完成，耗时：{}毫秒。", (t2 - t1));
	}
}
